function dart_detection(path, filename, initframes)
% DART_DETECTION is the main routine.
%
% Project:  Dart detection [Bildfolgen LU]@CVL/TUWIEN
% Author:   Thomas Rittler
% Date:     05/2011

global dbdef mkdef

GRAPHIC_OUTPUT = true;     % visual output
STEP = 100;     % number of frames loaded at once

suffix = {'Cam1', 'Cam2'};
FILE_EXT = 'avi';
fid = fopen(sprintf('%s_punkte.txt', filename), 'w');

ALPHA_BG = .20;%.05;

fprintf(1,'Gruppe 10 - DART DETECTION:\n---------------------------\n\n');
fprintf(1, 'Path: \t\t%s\nFilename: \t%s.%s\nInitframes: %i\n',...
    path, filename, FILE_EXT, initframes);


refdb = imread('board.png');    % reference dart board

try
    % Cam1
    mov1 = mmreader(sprintf('%s%s_%s.%s', path, filename, suffix{1}, FILE_EXT));
    sz = [mov1.Height mov1.Width 3];
    frames(1) = mov1.NumberOfFrames;
    
    % Cam2
    mov2 = mmreader(sprintf('%s%s_%s.%s', path, filename, suffix{2}, FILE_EXT));
    frames(2) = mov2.NumberOfFrames;
catch exception
    fprintf(1, 'ERROR: File %s%s_{%s|%s}.%s not found! (%s)\n\n', path, filename,...
        suffix{1}, suffix{2}, FILE_EXT, exception.identifier);
end
frames = min(frames); % VIDEO1 CAM2 1 FRAME WENIGER!!
fprintf(1, 'Frames: \t%i\n\n', frames);


% initizialisation
fprintf(1,'1. Init background models:\n');
mu1 = zeros(sz);
vari1 = zeros(sz);
mu2 = zeros(sz);
vari2 = zeros(sz);
% default values
db1def = zeros(initframes, 2);    % dart board width
db2def = zeros(initframes, 2);
mk1def = zeros(initframes, 2);     % marker position (field 20|11)
mk2def = zeros(initframes, 2);

fprintf(1, ' Determine background parameters...\n\n\n\n\n\n\n'); tic;
i = 0;
frmstep = STEP:STEP:initframes;
if mod(initframes, STEP)
    frmstep = [frmstep initframes];
end
% init background model
for fr = 1:numel(frmstep)
    fridx = [i*STEP+1 frmstep(fr)];  % frame indices
    frms1 = mov1.read(fridx);
    frms2 = mov2.read(fridx);
    
    for idx = 1:diff(fridx)+1
        nidx = idx+i*STEP;
       
        % Cam1
        I1 = double(frms1(:,:,:,idx));
        xn_1 = I1-mu1;
        mu1 = mu1 + xn_1/nidx;
        vari1 = vari1+xn_1.*(I1-mu1);
        [db1def(nidx, :)  mk1def(nidx, :)] = getDartBoard(I1);
        
        % Cam2
        I2 = double(frms2(:,:,:,idx)); 
        xn_1 = I2-mu2;
        mu2 = mu2 + xn_1/nidx;
        vari2 = vari2+xn_1.*(I2-mu2);
        [db2def(nidx, :)  mk2def(nidx, :)] = getDartBoard(I2);
        
        fprintf(1, '\b\b\b\b\b\b\b%6.2f%%', nidx/initframes*100);
    end
    i = i+1;
    clear frms1 frms2;
end
fprintf(1, '\t\t(%5.2f sec)\n', toc);
clear I1 I2 xn_1;

vari1 = vari1/initframes;
vari2 = vari2/initframes;
dbdef(1,:) = median(db1def);
dbdef(2,:) = median(db2def);
mkdef(1,:) = median(mk1def);
mkdef(2,:) = median(mk2def);


fprintf(1,'\n2. Dart detection:\n');
fprintf(1, ' Running dart counter...\n\n\n\n\n\n\n'); tic;
DART_SZ = 12000;
motion = false;
collect = false;                    % darts collected
prefm1 = false(sz([1 2]));          % previous frame FM1
prefm2 = false(sz([1 2]));          % previous frame FM2
lastfm1 = false(sz([1 2]));         % last detected FM1/dart
lastfm2 = false(sz([1 2]));         % last detected FM2/dart
detectedfm1 = false(sz([1 2]));     % all detected FM/darts
detectedfm1BU = false(sz([1 2]));   % all detected FM/darts backup
scores = [];                        % all thrown darts
ip1 = [0 0]; ip2 = [0 0];           % intersection points (dart coordinates)
cp = [0 0];                         % DB center point
ldidx = 0;                          % index of last detected dart
i=87;
xfr=8800;
frmstep = initframes+(i+1)*STEP+1:STEP:frames;
% frmstep = initframes+STEP+1:STEP:frames;
if mod(frames-initframes-1, STEP)
    frmstep = [frmstep frames];
end
for fr = 1:numel(frmstep)
    fridx = [initframes+i*STEP+1 frmstep(fr)];  % frame indices
    frms1 = mov1.read(fridx);
    frms2 = mov2.read(fridx);
    for idx = 1:diff(fridx)+1        
        nidx = initframes+idx+i*STEP;
        score = 'NULL';
        ip = [0 0];
        
        img1 = frms1(:,:,:,idx);
        %%%%%%%%%%%
        if nidx == xfr
            mu1 = double(img1);
        end
        %%%%%%%%%%
        [fm1 dif1] = getFGmask(img1, mu1, vari1);   % foreground mask
        
        img2 = frms2(:,:,:,idx);
        %%%%%%%%%%%
        if nidx == xfr
            mu2 = double(img2);
        end
        %%%%%%%%%%
        [fm2 dif2] = getFGmask(img2, mu2, vari2);
        
        fm1(lastfm1) = 0;
        fm2(lastfm2) = 0;
        
        fm1 = bwareaopen(fm1, 2000, 4);
        fm2 = bwareaopen(fm2, 2000, 4);
        
        ifm1 = repmat(fm1, [1 1 3]);    % indices for background update
        ifm2 = repmat(fm2, [1 1 3]);    
        
        % motion detected 
        if (sum(sum(fm1))~=0 || sum(sum(fm2))~=0) && ~collect
            motion = true;
            
            rpfm1 = regionprops(fm1, 'Orientation');
            rpfm2 = regionprops(fm2, 'Orientation');
            
            % FM in upper part of the image
            fm1row = find(sum(fm1, 2), 1, 'first');
            if isempty(fm1row)
                fm1row = 0;
            end
            
            % dart occluded Cam2
            if numel(rpfm1) == 1 && abs(rpfm1(1).Orientation) > 45 && numel(rpfm2) >=1 ...
               && abs(rpfm2(1).Orientation) < 45
                    fm2 = false(sz([1 2]));
            % but no dart
            elseif numel(rpfm1) >= 2 || (numel(rpfm1) == 1 && abs(rpfm1(1).Orientation) < 45) ...
                    || numel(rpfm2) >= 2 || (numel(rpfm2) == 1 && abs(rpfm2(1).Orientation) < 45) ...
                    || (fm1row > 5 && fm1row < 30)
                motion = false;
                ifm1 = false([sz([1 2]) 3]);
                ifm2 = false([sz([1 2]) 3]);
            end
        end
        
        % darts collected and FM was reset
        if sum(sum(fm1))>DART_SZ*5 
            collect = true;
            if sum(sum(detectedfm1)) == 0
                detectedfm1 = detectedfm1BU;
            end
        end
        
        % dart detected
        if(motion && ~collect)
            md1 = abs(fm1-prefm1);   % compare to previous foreground mask
            md1 = bwareaopen(md1, 400, 8);
            md2 = abs(fm2-prefm2);
            md2 = bwareaopen(md2, 400, 8);
            
            % no changes between actual and previous foreground masks
            if sum(sum(md1))==0 && sum(sum(md2))==0 && sum(sum(fm1))<DART_SZ;
                % foreground mask not empty
                if sum(sum(bwareaopen(fm1, 200, 4)))~=0 || sum(sum(bwareaopen(fm2, 200, 4)))~=0 
                    [db mk] = checkDBValues(img1, img2); % dartboard values
                    db1 = db(1,:); db2 = db(2,:);
                    mk1 = mk(1,:); mk2 = mk(2,:);
                    ratio = diff(db1)/diff(db2);
                    cp(1) = mk1(1)+diff(mk1)/2-db1(1);  % center point
                    cp(2) = mk2(1)+diff(mk2)/2-db2(1);
                    cp(2) = cp(2)*ratio;
                    %                     cp(1) = diff(db1)/2; cp(2) = diff(db1)/2;           
                    
                    %%%%%%%%%%%%
                    GUESS = '';
                    try
                        ip1 = getIntersec(fm1);
                    catch
                        if sum(sum(lastfm1))~=0
                            ip1 = getIntersec(lastfm1);
                        else
                            ip1 = getIntersec(lastfm1BU);
                        end
                            GUESS = '???';
                    end
                    try
                        ip2 = getIntersec(fm2);
                    catch
                        if sum(sum(lastfm2))~=0
                            ip2 = getIntersec(lastfm2);
                        else
                            ip2 = getIntersec(lastfm2BU);
                        end
                        GUESS = '???';
                    end
                    
                    %%%%%%%%%%%% ????????????????
                    ip = [db1(2)-ip1(1) ip2(1)*ratio-db1(1)];   % intersection point
                    ip = ip + diff(abs(db-mk),1,2)'/2;
%                     ip(2) = ip(2)+10;
                    %%%%%%%%%%%%%%%%%
                    %ip = [db1(2)-getIntersec(fm1) getIntersec(fm2)*ratio-db1(1)];   % intersection point
                    score = getScore(diff(db1)/2, cp, ip);      % player score 
%                     score = getScore(cp(1), cp, ip);      % player score 
                    
                    
                    % dart detected twice (video out of sync) => remove 2nd last
                    if nidx-1-ldidx < 10
                        fclose('all');
                        movefile(sprintf('%s_punkte.txt', filename), 'tmp.txt');
                        tmpfid = fopen('tmp.txt');
                        fid = fopen(sprintf('%s_punkte.txt', filename), 'w');
                        while ~feof(tmpfid)
                            tline = fgets(tmpfid);
                            if tline ~= -1
                                tokens = regexp(tline, ';', 'split');
                                if str2double(tokens{1}) == ldidx;
                                else
                                    fwrite(fid,tline);
                                end
                            end
                        end
                        fclose(tmpfid);
                        delete('tmp.txt');
                    end
                    fprintf(fid, '%i;%s%s\n', nidx-1, score, GUESS);
                        
                    ldidx = nidx-1;
                    motion = false;
                    if sum(sum(fm1)) ~= 0
                        lastfm1 = imfill(fm1, 'holes');
                    end
                    if sum(sum(fm2)) ~= 0
                        lastfm2 = imfill(fm2, 'holes');
                    end
                    detectedfm1 = detectedfm1 | lastfm1;
                    mu1 = double(img1);
                    mu2 = double(img2);
                    scores = [scores; ip/diff(db1)*2000];
%                     scores = [scores; ip/(2*cp(1))*2000];
                else % ap
                    fprintf(fid, '%i;ap\n', nidx-3);
                    score = 'ap';
                    motion = false;
                    mu1 = double(img1);
                    mu2 = double(img2);
                end
                
            end
        end
        
        % darts collected (reset)
        if collect
            ifm1 = false([sz([1 2]) 3]);
            ifm2 = false([sz([1 2]) 3]);
            ALPHA_BG = .05;
            tmpfm1 = fm1;
            tmpfm1(detectedfm1|detectedfm1BU) = 0;
            if sum(sum(bwareaopen(tmpfm1, 6500, 4)))==0 % 4000
                mu1 = double(img1); mu2 = double(img2);
                if sum(sum(detectedfm1)) ~= 0
                    detectedfm1BU = detectedfm1;
                end
                detectedfm1 = false(sz([1 2]));
                if sum(sum(lastfm1)) ~= 0
                    lastfm1BU = lastfm1;
                end
                lastfm1 = false(sz([1 2]));
                if sum(sum(lastfm2)) ~= 0
                    lastfm2BU = lastfm2;
                end
                lastfm2 = false(sz([1 2]));
                collect = false;
                motion = false;
                ALPHA_BG = .20;
            end
        end
        %else
            % update BG
            mu1(~ifm1) = (1-ALPHA_BG)*mu1(~ifm1) + ALPHA_BG*double(img1(~ifm1));
            vari1(~ifm1) = (1-ALPHA_BG)*vari1(~ifm1)+ ALPHA_BG*dif1(~ifm1).^2;
            
            mu2(~ifm2) = (1-ALPHA_BG)*mu2(~ifm2) + ALPHA_BG*double(img2(~ifm2));
            vari2(~ifm2) = (1-ALPHA_BG)*vari2(~ifm2)+ ALPHA_BG*dif2(~ifm2).^2;
        %end
        
        % plots
        if(GRAPHIC_OUTPUT)  
            rp = regionprops(fm1, 'Area', 'Centroid', 'MajorAxisLength',...
                'MinorAxisLength', 'Orientation');
            
            rp2 = regionprops(fm2, 'Area', 'Centroid', 'MajorAxisLength',...
                'MinorAxisLength', 'Orientation');
            
            % forground mask Cam1
            subplot(334)
            imshow(fm1);
            title('FM1 + Ellipse');
            hold on;
            
            % bounding ellipse
            for bl = 1:numel(rp)    % all blobs
                el = getEllipse(rp(bl).MajorAxisLength/2, rp(bl).MinorAxisLength/2,...
                    rp(bl).Centroid(1), rp(bl).Centroid(2), rp(bl).Orientation*-1*pi/180); % own ellipse
                
                el(el(:,1)<1,1) = 1; el(el(:,1)>size(fm1,2),1) = size(fm1,2);
                el(el(:,2)<1,2) = 1; el(el(:,2)>size(fm1,1),2) = size(fm1,1);
                plot(el(:,1), el(:,2), 'c');
                
                % major axis
                x = -1000:1:1000;
                y = ones(1, numel(x));
                xm = rp(bl).Centroid(1);
                ym = rp(bl).Centroid(2);
                
                theta = 180+rp(bl).Orientation + (90-rp(bl).Orientation)*2;
                R = [cosd(theta) sind(theta); -sind(theta) cosd(theta)];
                ln = [x' y']*R;
                ln(:,1) = ln(:,1)+xm;
                ln(:,2) = ln(:,2)+ym;
                plot(ln(:,1), ln(:,2), 'r-');
            end
            hold off;
            
            % forground mask Cam2
            subplot(336)
            imshow(fm2);
            title('FM2 + Ellipse');
            hold on;
            
            % bounding ellipse
            for bl = 1:numel(rp2)    % all blobs
                el = getEllipse(rp2(bl).MajorAxisLength/2, rp2(bl).MinorAxisLength/2,...
                    rp2(bl).Centroid(1), rp2(bl).Centroid(2), rp2(bl).Orientation*-1*pi/180); % own ellipse
                
                el(el(:,1)<1,1) = 1; el(el(:,1)>size(fm1,2),1) = size(fm1,2);
                el(el(:,2)<1,2) = 1; el(el(:,2)>size(fm1,1),2) = size(fm1,1);
                plot(el(:,1), el(:,2), 'c');
                
                % major axis
                x = -1000:1:1000;
                y = ones(1, numel(x));
                xm = rp2(bl).Centroid(1);
                ym = rp2(bl).Centroid(2);
                
                theta = 180+rp2(bl).Orientation + (90-rp2(bl).Orientation)*2;
                R = [cosd(theta) sind(theta); -sind(theta) cosd(theta)];
                ln = [x' y']*R;
                ln(:,1) = ln(:,1)+xm;
                ln(:,2) = ln(:,2)+ym;
                plot(ln(:,1), ln(:,2), 'r-');
            end
            hold off;
            
            % background Cam1
            subplot(337)
            imshow(uint8(mu1))
            title(sprintf('MU1\n (%6.2f,  %6.2f,  %6.2f)', max(max(vari1(:,:,1))),...
                max(max(vari1(:,:,2))), max(max(vari1(:,:,3)))));
            
            % background Cam2
            subplot(339)
            imshow(uint8(mu2))
            title(sprintf('MU2\n (%6.2f,  %6.2f,  %6.2f)', max(max(vari2(:,:,1))),...
                max(max(vari2(:,:,2))), max(max(vari2(:,:,3)))));
            
            % Cam1 plus dartboard boundaries
            subplot(331)
            imshow(img1)
            hold on;
            [db mk] = checkDBValues(img1, img2);
            board = db(1,:); board2 = db(2,:);
            field = mk(1,:); field2 = mk(2,:);
            Xv = [board(1) board(2); board(1) board(2)];
            Xf = [field(1) field(2); field(1) field(2)];
            Yv = [1 1; size(img1, 2) size(img1,2)];
            line(Xv,Yv,  'Color', 'r');
            line(Xf,Yv, 'Color', 'g');
            plot(ip1(1), ip1(2), 'rx');
            hold off;
            title(sprintf('Dart board C1 (%i, %i, %i)',...
                round(field(1)-board(1)), round(board(2)-field(2)), round(field(2)-field(1))))
            
            % Cam2 plus dartboard boundaries
            subplot(333)
            imshow(img2)
            hold on;
            Xv = [board2(1) board2(2); board2(1) board2(2)];
            Xf = [field2(1) field2(2); field2(1) field2(2)];
            line(Xv,Yv,  'Color', 'r');
            line(Xf,Yv, 'Color', 'g');
            plot(ip2(1), ip2(2), 'rx');
            hold off;
            title(sprintf('Dart board C2 (%i, %i, %i)',...
                round(field2(1)-board2(1)), round(board2(2)-field2(2)), round(field(2)-field(1))))
            
            if nidx == 8595
                 PAUSE = 1;
            end
            
            % reference dartboard
            subplot(335)
            imshow(refdb);
            axis off;
            hold on;
            rip = ip/diff(board)*2000;
            plot(rip(1), rip(2), 'mo', 'MarkerSize', 11, 'LineWidth', 2);
            plot(rip(1), rip(2), 'mx', 'MarkerSize', 11, 'LineWidth', 2);
            hold off;
            title(sprintf('%i;%s (M:%i,C:%i,A:%i)', nidx-1, score, motion, collect,sum(sum(fm1))));
            
            % detected darts Cam1
            subplot(332)
            imshow(detectedfm1);
            title('Detected FM1');
            
            % forground mask minus detected darts Cam1
            subplot(338)
            tempfm = fm1;
            tempfm(detectedfm1|detectedfm1BU) = 0;
            imshow(bwareaopen(tempfm, 6500, 4))
            title('FM1 - detectedfm1 + areaopen');
            
            drawnow;
        end
        
        fprintf(1, '\b\b\b\b\b\b\b%6.2f%%', (nidx-initframes)/(frames-initframes)*100);
        
        % previous foreground mask
        prefm1 = fm1;
        prefm2 = fm2;
        
    end
    i = i+1;
    clear frms1 frms2;
end
fprintf(1, '\t(%5.2f sec)\n\n', toc);
fclose(fid);

% graphical dart distribution
save(sprintf('%s.mat', filename), 'scores');
figure;
imshow(refdb);
hold on;
smoothhist2D(scores, 80, [600 600], 0);
hold off;
% input('\nPress Enter to continue...\n');
end